#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 该文件用于对本地测试数据中的文件进行各种操作的方法

from .assert_tools import *
from .yaml_tools import *


class FileOp:

    def __init__(self, l_dir=None, log_n="log"):
        self.l_dir = l_dir
        self.log = log_n  # 定义日志存放的文件名

    def clear_dir(self, path_lst_index, module_n, lst_index):
        """用于清除本地目录下的文件(如有文件夹遍历文件夹)"""
        dir_path = Yl().get_mod_val(path_lst_index, module_n, lst_index)
        ls = os.listdir(dir_path)
        for i in ls:
            c_path = os.path.join(dir_path, i)
            if os.path.isdir(c_path):
                self.clear_dir(path_lst_index, module_n, lst_index)
            else:
                os.remove(c_path)

    def get_file_path(self, file_match=None):
        """
        功能:1获取本地测试数据目录下的所有文件的路径  2根据file_match匹配对应后缀的文件并获取路径
        file_match  文件后缀 如: mp4
        return 不传file_match则返回所有的文件路径列表  传file_match返回符合条件的文件路径列表
        """
        file_path_lst = []  # 用于存储获取到的本地目录下的文件路径
        count = 0
        # root当前目录的路径,dirs为该目录下的子目录,files为非目录文件(即文件)
        # log(self.log).info("您当前操作的本地测试数据目录路径为:" + s_str(self.dir))
        for root, dirs, files in os.walk(self.l_dir):
            for file in files:
                if file_match is not None:
                    if re.match(".+\\." + file_match, file):  # 匹配指定后缀的文件
                        file_path_lst.append(os.path.join(root, file))
                        count += 1
                else:
                    file_path_lst.append(os.path.join(root, file))
                    count += 1
        if len(file_path_lst) > 0:
            return file_path_lst
        else:
            Assert().fail_assert("目录:%s下没有任何文件,请检查本地测试数据!" % str(self.l_dir))

    def get_file_size(self):
        """
        获取文件夹内每个文件的大小,以列表形式返回
        """
        for root, dirs, files in os.walk(self.l_dir):
            file_size_lst = [getsize(join(root, name)) for name in files]
            return file_size_lst

    def get_file_name(self):
        """
        获取文件夹内每个文件的文件名,以列表形式返回
        """
        file_name_lst = []
        for folderName, subfolders, filenames in os.walk(self.l_dir):
            for filename in filenames:
                file_name_lst.append(filename)
        return file_name_lst

    def single_file_size(self, file_path):
        """
        获取单个文件大小
        file_path 文件路径
        """
        size = os.path.getsize(file_path)
        log(self.log).info("文件为:%s,文件的大小为:%s" % (str(file_path), str(size)))
        return size

    def single_file_md5(self, file_path):
        """
        获取单个文件MD5值
        file_path 文件路径
        """
        m = hashlib.md5()
        with open(file_path, 'rb') as f:
            for line in f:
                m.update(line)
        md5code = m.hexdigest()
        log(self.log).info("文件为:%s,文件的md5为:%s" % (str(file_path), str(md5code)))
        return md5code

    def get_file_mtime(self):
        """获取文件夹内每个文件的修改时间,以列表形式返回"""
        file_mtime_lst = []
        file_lst = self.get_file_path()
        for i in range(len(file_lst)):
            get_mtime = os.path.getmtime(file_lst[i])
            mtime = str(get_mtime).split(".")[0]
            file_mtime_lst.append(mtime)
        log(self.log).info("文件的修改时间为:%s" % str(file_mtime_lst))
        return file_mtime_lst

    def get_file_ext(self, ext=None):
        """获取文件夹内文件的扩展名(后缀)
        ext 指定后缀 返回指定后缀的文件完整路径列表 (ext填 ".jpg"  "jpg"均可)
            不指定后缀时返回所有文件的后缀
        """
        file_ext_lst = []
        if ext is None:
            for root, dirs, files in os.walk(self.l_dir):
                for filespath in files:
                    filepath = os.path.join(root, filespath)
                    extension = os.path.splitext(filepath)[1]  # 获取不带点的后缀如: hhh
                    file_ext_lst.append(extension)
        else:
            for root, dirs, files in os.walk(self.l_dir):
                for filespath in files:
                    filepath = os.path.join(root, filespath)
                    extension = os.path.splitext(filepath)[1][1:]  # 获取带点的后缀如: .hhh
                    if ext and extension in ext:
                        file_ext_lst.append(filepath)
                    elif not ext:
                        file_ext_lst.append(filepath)
            log(self.log).info("指定后缀的文件路径为:" + str(file_ext_lst))
        return file_ext_lst

    def file_ext_count(self):
        """获取文件夹内文件的扩展名(后缀)及统计每个后缀的个数,以字典形式返回"""
        ext_dict = {}
        for d, fd, fl in os.walk(self.l_dir):
            for f in fl:
                sufix = os.path.splitext(f)[1][1:]
                if sufix in ext_dict:
                    ext_dict[sufix] += 1
                else:
                    ext_dict[sufix] = 1
        log(self.log).info("文件路径下的各后缀数统计为:" + str(ext_dict))
        return ext_dict

    def video_duration(self, file_match, file_index=0):
        """
        获取某个视频文件的播放时长(如MP4,mkv等)
        file_match 需匹配的文件后缀
        file_index 匹配后在列表中的索引(即位置)
        """
        file_path = self.get_file_path(file_match)[file_index]
        cap = cv2.VideoCapture(file_path)
        if cap.isOpened():  # 当成功打开视频时cap.isOpened()返回True,否则返回False,get方法参数按顺序对应下表(从0开始编号)
            rate = cap.get(5)  # 获取帧率
            frame_num = cap.get(7)  # 获取帧数
            duration = frame_num / rate * 1000  # # 帧速率/视频总帧数 时间-秒(除以/60是分钟)
            log(self.log).info("文件路径下的视频时长为:" + str(duration))
            return duration
        return str(-1) + ",没有该视频文件请检查数据路径"

    def video_duration_split(self, file_match, file_index):
        """
        取视频时长值后将【数字转化为字符串处理】最终获取符合server取值格式的值
        file_match 需匹配的文件后缀
        file_index 匹配后在列表中的索引(即位置)
        """
        num = self.video_duration(file_match, file_index)
        xs_list = [1]  # 用于处理小数部分向上取值
        zs, xs = str(num).split('.')  # 将float转化成str,分整数部分和小数部分
        xs_list.append(int(xs[:3]))  # 用字符串切片函数将小数部分取前3位
        xs_2 = sum(xs_list)  # 处理小数部分向上取值(列表+1求和)
        final_duration = zs + str(xs_2)  # 拼接总时长(按server的时长取值)
        log(self.log).info("处理本地工程文件时长值,获取到符合server格式的视频时长为" + str(final_duration))
        return final_duration

    def resolution(self, f_path):
        """
        获取某个视频/图片文件的分辨率(如MP4,mkv等)----有长,宽值的文件
        return height-高
        """
        file = cv2.VideoCapture(f_path)
        width = int(file.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(file.get(cv2.CAP_PROP_FRAME_HEIGHT))
        log(self.log).info(f'文件的分辨率(宽-高)为:{width} x {height}')
        file.release()  # 释放资源,避免资源泄露或内存溢出
        return height

    def get_resolutio_file(self, val, file_match):
        """
        根据指定的分辨率值获取文件
        val 指定的分辨率值
        file_match 需匹配的文件后缀
        return 返回满足指定分辨率的文件路径
        """
        height_lst = []
        file_path_lst = self.get_file_path(file_match)
        for i in range(len(file_path_lst)):
            height = self.resolution(file_path_lst[i])
            height_lst.append(height)
        h_index = height_lst.index(val)
        file_path = file_path_lst[h_index]
        log(self.log).info("分辨率为:" + str(val) + "的文件路径为:" + str(file_path))
        return file_path

    def audio_info(self, file_match=None, file_index=None, file_path=None):
        """
        获取音频信息(作者/专辑/标题等)
        file_match 需匹配的文件后缀
        file_index 匹配后在列表中的索引(即位置)
        file_path 文件路径
        return 信息列表
        """
        if file_path is None:
            filepath = self.get_file_path(file_match)[file_index]
        else:
            filepath = file_path
        info_list = []
        audio = TinyTag.get(filepath)
        info_list.append(audio.artist)  # 作者
        info_list.append(audio.album)  # 专辑
        info_list.append(audio.title)  # 标题
        dur = audio.duration  # 时长
        duration = round(dur)  # 处理符合server四舍五入的取值方法
        info_list.append(duration)
        log(self.log).info("处理本地工程文件作者/专辑/标题等信息,获取到的值为" + str(info_list))
        return info_list

    def image_info(self, file_match, file_index):
        """
        获取图片信息(宽、高/类型等)
        file_match 需匹配的文件后缀
        file_index 匹配后在列表中的索引(即位置)
        """
        filepath = self.get_file_path(file_match)[file_index]
        img = Image.open(filepath)
        img_width_height = img.size  # 返回长和宽(元组)
        log(self.log).info("处理本地工程文件宽/高等信息,获取到的值为" + str(img_width_height))
        return img_width_height

    def pic_to_base64(self, file_match, file_index):
        """
        将图片转换为base64编码
        file_match 需匹配的文件后缀
        file_index 匹配后在列表中的索引(即位置)
        """
        f = open(self.get_file_path(file_match)[file_index], 'rb')  # 二进制方式打开图文件
        img_base64 = base64.b64encode(f.read())  # 读取文件内容,转换为base64编码
        # bytes类型需要转成string:用decode()转成string类型
        img_base64_str = img_base64.decode()
        log(self.log).info("将图片转换为base64编码,获取到的值为" + str(img_base64_str))
        return img_base64_str

    def base64_to_pic(self, file_match, file_index, name):
        """
        将图片base64编码,解码为图片
        file_match 需匹配的文件后缀
        file_index 匹配后在列表中的索引(即位置)

        """
        img_base64_data = base64.b64decode(self.pic_to_base64(file_match, file_index))  # 解码,将图片base64编码,解码为图片
        file = open(name + '.jpg', "wb")
        file.write(img_base64_data)
        file.close()

    def get_exif_value(self, file_path, exif_key, gps_info=None):
        """
        获取图片或者视频的EXIF相关信息
        file_path 文件路径
        exif_key-需要获取的值的项名,如果是GPS信息返回的是列表需要特殊处理GPS_info等于0为开启
        """
        f = open(file_path, 'rb')
        # 获取文件信息
        tags = exifread.process_file(f)
        if gps_info == 0:
            EXIF_values = tags.get(exif_key, "0").values
            EXIF_value = ""
            for j in EXIF_values:
                EXIF_value = str(EXIF_value) + str(j)
        else:
            EXIF_value = tags.get(exif_key, "0").values
        log(self.log).info("获取到EXIF的项名:" + exif_key + "的值为:" + EXIF_value)
        return EXIF_value

    def get_start_time(self, exif_key, gps_info=None, file_match="jpg"):
        """
        获取本地目录下照片的拍摄时间,用于添加专属回忆相册时的起/止时间
        file_match 需匹配的文件后缀
        """
        file_path = self.get_file_path(file_match)
        film_time_list = []
        for i in range(len(file_path)):
            str_time = self.get_exif_value(file_path[i], exif_key, gps_info)
            memory_start_time = int(time.mktime(time.strptime(str_time, "%Y:%m:%d %H:%M:%S")))
            film_time_list.append(memory_start_time)
            film_time_list.sort(reverse=False)  # 对获取到的拍摄时间进行升序排序
        return film_time_list
